/**
 * @file: rpc.js
 * @brief: WebSocket版本RPC远程调用功能实现，仅支持浏览器环境
 * @date: 2025-10-15
 *
 **************************/

/**
 * RPC客户端类
 * 用于发送RPC请求并处理响应
 */
class RpcClient {
    /**
     * 构造函数
     * @param {string} serverUrl - RPC服务器URL
     */
    constructor(serverUrl) {
        // 在Node.js环境中，默认使用localhost:8080
        this.serverUrl = serverUrl || 'localhost:8080';
        this.requestId = 0;
        this.callbacks = {};
        this.socket = null;
        this.isConnected = false;
    }

    /**
     * 发送RPC请求（使用JSON格式）
     * @param {string} method - RPC方法名
     * @param {object} params - RPC方法参数
     * @returns {Promise} - 返回Promise对象，解析为RPC响应结果
     */
    async call(method, params) {
        return new Promise((resolve, reject) => {
            if (!this.isConnected || !this.socket) {
                const error = new Error('RPC not connected');
                console.error(`RPC call to ${method} failed:`, error);
                reject(error);
                return;
            }

            const requestId = this.requestId++;
            const request = {
                "id": requestId,
                "method": method,
                "params": params
            };

            console.log(`发送RPC请求: method=${method}, params=`, params);

            // 保存回调函数
            this.callbacks[requestId] = (response) => {
                console.log(`收到RPC响应: method=${method}, response=`, response);
                
                if (response.error) {
                    reject(new Error(`RPC method failed: ${response.error.message || 'Unknown error'}`));
                } else {
                    // 检查响应格式，有些服务器可能直接返回结果而不是包装在result字段中
                    if (response.result !== undefined) {
                        resolve(response.result);
                    } else {
                        // 如果没有result字段，直接返回整个响应对象
                        console.log(`注意：响应中没有result字段，直接返回整个响应对象`);
                        resolve(response);
                    }
                }
            };

            try {
                this.socket.send(JSON.stringify(request));
            } catch (error) {
                console.error(`Failed to send RPC message:`, error);
                delete this.callbacks[requestId];
                reject(error);
            }
        });
    }

    /**
     * 连接RPC服务器
     * @returns {Promise} - 返回连接结果的Promise
     */
    connectRpc() {
        return new Promise((resolve, reject) => {
            try {
                // 浏览器环境下直接使用WebSocket API
                if (typeof WebSocket === 'undefined') {
                    throw new Error('WebSocket is not supported in this browser');
                }
                
                // 解析服务器地址并添加WebSocket协议前缀
                let wsUrl = this.serverUrl;
                if (!wsUrl.startsWith('ws://') && !wsUrl.startsWith('wss://')) {
                    // 如果没有协议前缀，默认为ws://
                    const parts = wsUrl.split(':');
                    const host = parts[0];
                    const port = parseInt(parts[1]) || 8080;
                    wsUrl = `ws://${host}:${port}`;
                }
                
                // 创建WebSocket连接
                this.socket = new WebSocket(wsUrl);

                // WebSocket事件处理
                this.socket.onopen = () => {
                    console.log('RPC WebSocket connection established');
                    this.isConnected = true;
                    resolve();
                };

                // 处理接收到的消息
                this.socket.onmessage = (event) => {
                    try {
                        // WebSocket已经处理了消息边界，直接解析JSON
                        const response = JSON.parse(event.data);
                        const id = response["id"];
                        
                        if (id !== undefined && this.callbacks[id]) {
                            this.callbacks[id](response);
                            delete this.callbacks[id];
                        } else {
                            console.warn('Received RPC response with unknown or missing ID:', response);
                        }
                    } catch (error) {
                        console.error('Failed to parse RPC response:', error);
                    }
                };

                this.socket.onclose = () => {
                    console.log('RPC WebSocket connection closed');
                    this.isConnected = false;
                };

                this.socket.onerror = (error) => {
                    console.error('RPC WebSocket connection error:', error);
                    this.isConnected = false;
                    reject(error);
                };
            } catch (error) {
                console.error('Failed to create WebSocket connection:', error);
                reject(error);
            }
        });
    }



    /**
     * 关闭RPC连接
     */
    disconnectRpc() {
        if (this.socket) {
            this.socket.close();
            this.socket = null;
            this.isConnected = false;
            this.callbacks = {};
        }
    }

    /**
     * 检查连接状态
     * @returns {boolean} - 返回连接状态
     */
    isConnected() {
        return this.isConnected;
    }
}

/**
 * Lua RPC接口封装
 */
class LuaRpc {
    /**
     * 构造函数
     * @param {RpcClient} rpcClient - RPC客户端实例
     */
    constructor(rpcClient) {
        this.rpcClient = rpcClient;
        this.luaId = null; // 保存当前使用的Lua环境ID
    }

    /**
     * 创建Lua运行环境
     * @returns {Promise<number>} - 返回Lua环境ID
     */
    async create() {
        console.log('LuaRpc.create() 被调用');
        try {
            const result = await this.rpcClient.call('lua.create', "NULL");
            
            // 详细打印返回结果，以便分析数据结构
            console.log('服务器返回完整结果:', result);
            console.log('结果类型:', typeof result);
            
            if (typeof result === 'object' && result !== null) {
                this.luaId = result['lua_id'] || null;
                
                if (this.luaId !== null) {
                    console.log(`Lua环境创建成功，luaId: ${this.luaId}`);
                    return this.luaId;
                } else {
                    // 遍历对象的所有键，查看有哪些可用字段
                    const availableKeys = Object.keys(result);
                    console.error(`无法找到lua_id字段，可用字段: ${availableKeys.join(', ')}`);
                    throw new Error(`无法在响应中找到lua_id字段，可用字段: ${availableKeys.join(', ')}`);
                }
            } else {
                console.error('服务器返回的结果不是有效的对象:', result);
                throw new Error('服务器返回的结果不是有效的对象');
            }
        } catch (error) {
            console.error('Lua环境创建失败:', error);
            throw error;
        }
    }

    /**
     * 执行Lua代码
     * @param {string} code - Lua代码字符串
     * @returns {Promise<void>}
     * @description: 不需要传入lua_id参数，如果lua_id为空则自动创建新的Lua环境
     */
    async runCode(code) {
        console.log(`LuaRpc.runCode() 被调用，当前luaId: ${this.luaId}`);
        
        // 记录执行前的环境ID，用于后续比较
        const originalLuaId = this.luaId;
        
        // 如果没有保存的luaId，自动创建新的Lua环境
        if (!this.luaId) {
            console.warn('Lua环境ID为空，正在自动创建新的Lua环境');
            try {
                console.time('创建Lua环境耗时');
                await this.create();
                console.timeEnd('创建Lua环境耗时');
                
                // 再次检查环境是否创建成功
                if (!this.luaId) {
                    console.error('自动创建Lua环境失败，luaId仍为空');
                    throw new Error('自动创建Lua环境失败，luaId仍为空');
                }
                
                console.log(`Lua环境创建成功，新的luaId: ${this.luaId}`);
            } catch (error) {
                console.error('自动创建Lua环境失败:', error);
                throw error;
            }
        }
        
        try {
            console.log(`准备执行Lua代码，使用luaId: ${this.luaId}`);
            console.time('执行Lua代码耗时');
            
            const result = await this.rpcClient.call('lua.runCode', {
                'lua_id': this.luaId,
                'code': code
            });
            
            console.timeEnd('执行Lua代码耗时');
            
            // 检查返回结果是否包含错误
            // 获取返回结果中的错误信息
            const retCode = result['ret'] || null;
            const retMessage = result['ret_message'] || null;
            
            if (retCode !== 0 && retCode !== null) {
                console.error(`Lua代码执行失败，错误码: ${retCode}，错误消息: ${retMessage || 'Unknown error'}`);
                throw new Error(retMessage || 'Failed to execute Lua code');
            }
            
            console.log(`Lua代码执行成功，使用的luaId: ${this.luaId}`);
            
            // 验证执行前后是否使用了相同的环境ID
            if (originalLuaId && originalLuaId !== this.luaId) {
                console.warn(`警告: Lua环境ID在执行过程中发生变化，从 ${originalLuaId} 变为 ${this.luaId}`);
            }
        } catch (error) {
            console.error('执行Lua代码时出错:', error);
            throw error;
        }
    }

    /**
     * 运行Lua文件
     * @param {string} filePath - Lua文件路径
     * @returns {Promise<void>}
     * @description: 不需要传入lua_id参数，如果lua_id为空则自动创建新的Lua环境
     */
    async runFile(filePath) {
        console.log(`LuaRpc.runFile() 被调用，文件路径: ${filePath}，当前luaId: ${this.luaId}`);
        
        // 记录执行前的环境ID，用于后续比较
        const originalLuaId = this.luaId;
        
        // 如果没有保存的luaId，自动创建新的Lua环境
        if (!this.luaId) {
            console.warn('Lua环境ID为空，正在自动创建新的Lua环境');
            try {
                console.time('创建Lua环境耗时');
                await this.create();
                console.timeEnd('创建Lua环境耗时');
                
                // 再次检查环境是否创建成功
                if (!this.luaId) {
                    console.error('自动创建Lua环境失败，luaId仍为空');
                    throw new Error('自动创建Lua环境失败，luaId仍为空');
                }
            } catch (error) {
                console.error('自动创建Lua环境失败:', error);
                throw error;
            }
        }
        
        try {
            console.log(`准备运行Lua文件: ${filePath}，使用luaId: ${this.luaId}`);
            console.time('运行文件耗时');
            
            const result = await this.rpcClient.call('lua.runFile', {
                'lua_id': this.luaId,
                'file_path': filePath
            });
            
            console.timeEnd('运行文件耗时');
            
            // 检查返回结果是否包含错误
            if (result && typeof result === 'object') {
                // 获取返回结果中的错误信息
                const retCode = result['ret'] || null;
                const retMessage = result['ret_message'] || null;
                
                if (retCode !== 0 && retCode !== null) {
                    console.error(`运行文件失败，错误码: ${retCode}，错误消息: ${retMessage || 'Unknown error'}`);
                    throw new Error(retMessage || 'Failed to run Lua file');
                }
            }
            
            console.log(`运行文件成功: ${filePath}`);
            
            // 验证执行前后是否使用了相同的环境ID
            if (originalLuaId && originalLuaId !== this.luaId) {
                console.warn(`警告: Lua环境ID在执行过程中发生变化，从 ${originalLuaId} 变为 ${this.luaId}`);
            }
        } catch (error) {
            console.error(`运行文件 ${filePath} 时出错:`, error);
            throw error;
        }
    }

    /**
     * 销毁Lua环境
     * @returns {Promise<void>}
     */
    async destroy() {
        console.log(`LuaRpc.destroy() 被调用，当前luaId: ${this.luaId}`);
        
        if (this.luaId) {
            try {
                console.time('销毁Lua环境耗时');
                
                const result = await this.rpcClient.call('lua.destroy', {
                    'lua_id': this.luaId
                });
                
                console.timeEnd('销毁Lua环境耗时');
                
                // 检查返回结果是否包含错误
                if (result && typeof result === 'object') {
                    // 获取返回结果中的错误信息
                    const retCode = result['ret'] || null;
                    const retMessage = result['ret_message'] || null;
                    
                    if (retCode !== 0 && retCode !== null) {
                        console.error(`销毁Lua环境失败，错误码: ${retCode}，错误消息: ${retMessage || 'Unknown error'}`);
                        // 即使销毁失败，也将本地记录的luaId设为null，因为服务端可能已经处理
                        this.luaId = null;
                        throw new Error(retMessage || 'Failed to destroy Lua environment');
                    }
                }
                
                // 成功销毁后，清空luaId
                this.luaId = null;
                console.log('Lua环境已成功销毁');
            } catch (error) {
                console.error('销毁Lua环境时出错:', error);
                // 即使销毁出错，也将本地记录的luaId设为null，因为服务端可能已经处理
                this.luaId = null;
                throw error;
            }
        } else {
            console.log('没有有效的Lua环境ID可销毁');
        }
    }

    /**
     * 设置Lua全局变量
     * @param {string} name - 变量名
     * @param {any} value - 变量值
     * @returns {Promise<void>}
     * @description: 不需要传入lua_id参数，如果lua_id为空则自动创建新的Lua环境
     */
    async setGlobal(name, value) {
        console.log(`LuaRpc.setGlobal() 被调用，变量名: ${name}，当前luaId: ${this.luaId}`);
        
        // 记录执行前的环境ID，用于后续比较
        const originalLuaId = this.luaId;
        
        // 如果没有保存的luaId，自动创建新的Lua环境
        if (!this.luaId) {
            console.warn('Lua环境ID为空，正在自动创建新的Lua环境');
            try {
                console.time('创建Lua环境耗时');
                await this.create();
                console.timeEnd('创建Lua环境耗时');
                
                // 再次检查环境是否创建成功
                if (!this.luaId) {
                    console.error('自动创建Lua环境失败，luaId仍为空');
                    throw new Error('自动创建Lua环境失败，luaId仍为空');
                }
            } catch (error) {
                console.error('自动创建Lua环境失败:', error);
                throw error;
            }
        }
        
        try {
            console.log(`准备设置Lua全局变量: ${name} = ${JSON.stringify(value)}，使用luaId: ${this.luaId}`);
            console.time('设置变量耗时');
            
            const result = await this.rpcClient.call('lua.setGlobal', {
                'lua_id': this.luaId,
                'name': name,
                'value': value
            });
            
            console.timeEnd('设置变量耗时');
            
            // 检查返回结果是否包含错误
            // 获取返回结果中的错误信息
            const retCode = result['ret'] || null;
            const retMessage = result['ret_message'] || null;
            
            if (retCode !== 0 && retCode !== null) {
                console.error(`设置变量失败，错误码: ${retCode}，错误消息: ${retMessage || 'Unknown error'}`);
                // 保留原始错误消息，而不是使用通用错误消息
                throw new Error(retMessage || 'Failed to set global variable');
            }
            
            console.log(`设置变量成功: ${name} = ${JSON.stringify(value)}`);
            
            // 验证执行前后是否使用了相同的环境ID
            if (originalLuaId && originalLuaId !== this.luaId) {
                console.warn(`警告: Lua环境ID在执行过程中发生变化，从 ${originalLuaId} 变为 ${this.luaId}`);
            }
        } catch (error) {
            console.error(`设置变量 ${name} 时出错:`, error);
            throw error;
        }
    }

    /**
     * 获取Lua全局变量
     * @param {string} name - 变量名
     * @returns {Promise<Object>} - 返回包含变量值和状态信息的对象
     * @description: 不需要传入lua_id参数，如果lua_id为空则自动创建新的Lua环境
     */
    async getGlobal(name) {
        console.log(`LuaRpc.getGlobal() 被调用，变量名: ${name}，当前luaId: ${this.luaId}`);
        
        // 记录执行前的环境ID，用于后续比较
        const originalLuaId = this.luaId;
        
        // 如果没有保存的luaId，自动创建新的Lua环境
        if (!this.luaId) {
            console.warn('Lua环境ID为空，正在自动创建新的Lua环境');
            try {
                console.time('创建Lua环境耗时');
                await this.create();
                console.timeEnd('创建Lua环境耗时');
                
                // 再次检查环境是否创建成功
                if (!this.luaId) {
                    console.error('自动创建Lua环境失败，luaId仍为空');
                    throw new Error('自动创建Lua环境失败，luaId仍为空');
                }
            } catch (error) {
                console.error('自动创建Lua环境失败:', error);
                throw error;
            }
        }
        
        try {
            console.log(`准备获取Lua全局变量: ${name}，使用luaId: ${this.luaId}`);
            console.time('获取变量耗时');
            
            const result = await this.rpcClient.call('lua.getGlobal', {
                'lua_id': this.luaId,
                'name': name
            });
            
            console.timeEnd('获取变量耗时');
            
            // 检查返回结果是否包含错误
            // 获取返回结果中的错误信息
            const retCode = result['ret'] || null;
            const retMessage = result['ret_message'] || null;
            
            if (retCode !== 0 && retCode !== null) {
                console.error(`获取变量失败，错误码: ${retCode}，错误消息: ${retMessage || 'Unknown error'}`);
                // 保留原始错误消息，而不是使用通用错误消息
                throw new Error(retMessage || 'Failed to get global variable');
            }
            
            console.log(`获取变量成功: ${name}`);
            
            // 验证执行前后是否使用了相同的环境ID
            if (originalLuaId && originalLuaId !== this.luaId) {
                console.warn(`警告: Lua环境ID在执行过程中发生变化，从 ${originalLuaId} 变为 ${this.luaId}`);
            }
            
            // 返回包含变量值和状态信息的完整对象
            return {
                value: result['value'] || null,
                ret: retCode,
                retMessage: retMessage
            };
        } catch (error) {
            console.error(`获取变量 ${name} 时出错:`, error);
            throw error;
        }
    }


}

// 浏览器环境中，添加到全局对象
if (typeof self !== 'undefined') {
    self.RpcClient = RpcClient;
    self.LuaRpc = LuaRpc;
}

// 兼容旧版浏览器的window对象
if (typeof window !== 'undefined') {
    window.RpcClient = RpcClient;
    window.LuaRpc = LuaRpc;
}